#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <cstdio>
#include <memory>
#include <filesystem>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "../../mqcommon/logger.hpp"

class FileHelper
{
public:
    FileHelper(std::string filename)
        : _filename(filename)
    {
    }

    // 如果你用的是 C++17 及以上版本，可以使用 std::filesystem，这是一种更现代、更优雅的方式
    bool exist()
    {
        return std::filesystem::exists(_filename);
    }

    // C++ 规定 seekg() 需要传入 std::ios::beg 作为参考点
    //
    int size()
    {
        // 使用 std::ios::ate这个标志 (ate = "at end") 让 ifstream 在打开文件时直接跳到末尾，
        // 然后我们可以直接调用 tellg() 获取大小，无需手动调用 seekg()，这样代码更简洁高效。
        std::ifstream in(_filename, std::ios::binary | std::ios::ate);
        if (!in.is_open())
        {
            ELOG("无法打开文件 %s", _filename.c_str());
            return -1;
        }

        std::streamsize length = in.tellg();
        if (length < 0)
        {
            ELOG("无法获取文件大小 %s", _filename.c_str());
            in.close();
            return -1;
        }

        in.close();
        return static_cast<size_t>(length);
    }

    int read(std::vector<char> &buffer)
    {
        std::ifstream in(_filename, std::ios::binary);
        if (!in.is_open())
        {
            ELOG("无法打开文件 %s", _filename.c_str());
            return -1;
        }

        // 获取文件大小
        in.seekg(0, std::ios::end);
        size_t file_size = in.tellg();
        in.seekg(0, std::ios::beg);

        // 调用已有的 read() 读取整个文件
        int ret = read(buffer, 0, file_size);
        in.close();

        return ret;
    }

    int read(std::string &buffer)
    {
        std::ifstream in(_filename, std::ios::binary);
        if (!in.is_open())
        {
            ELOG("无法打开文件 %s", _filename.c_str());
            return -1;
        }

        // 获取文件大小
        in.seekg(0, std::ios::end);
        size_t file_size = in.tellg();
        in.seekg(0, std::ios::beg);

        // 调用已有的 read() 读取整个文件
        int ret = read(buffer, 0, file_size);
        in.close();

        return ret;
    }

    int read(std::vector<char> &buffer, size_t pos, size_t len)
    {
        std::ifstream in(_filename, std::ios::binary);
        if (!in.is_open())
        {
            ELOG("无法打开文件 %s", _filename.c_str());
            return -1;
        }

        // 先尝试定位到 pos 位置
        if (!in.seekg(pos))
        {
            ELOG("文件 %s 的偏移 %zu 无效", _filename.c_str(), pos);
            in.close();
            return -1;
        }

        // 预分配空间
        buffer.resize(len);

        // 读取文件内容
        in.read(buffer.data(), len);
        size_t read_len = in.gcount(); // 获取实际读取的字节数

        // 处理可能的读取不足情况
        if (read_len < len)
        {
            ELOG("文件 %s 读取数据不足: 期望 %zu 字节，实际 %zu 字节", _filename.c_str(), len, read_len);
            buffer.resize(read_len); // 调整 vector 大小
        }
        in.close();

        return static_cast<int>(read_len);
    }

    int read(std::string &buffer, size_t pos, size_t len)
    {
        std::ifstream in(_filename, std::ios::binary);
        if (!in.is_open())
        {
            ELOG("无法打开文件 %s", _filename.c_str());
            return -1;
        }

        // 先尝试定位到 pos 位置
        if (!in.seekg(pos))
        {
            ELOG("文件 %s 的偏移 %zu 无效", _filename.c_str(), pos);
            in.close();
            return -1;
        }

        // 预分配空间
        buffer.resize(len);

        // 读取文件内容
        in.read(buffer.data(), len);
        size_t read_len = in.gcount(); // 获取实际读取的字节数

        // 处理可能的读取不足情况
        if (read_len < len)
        {
            ELOG("文件 %s 读取数据不足: 期望 %zu 字节，实际 %zu 字节", _filename.c_str(), len, read_len);
            buffer.resize(read_len); // 调整 vector 大小
        }
        in.close();

        return static_cast<int>(read_len);
    }

    int write(const std::string &buffer, size_t pos, size_t len)
    {
        std::ofstream out(_filename, std::ios::binary | std::ios::in | std::ios::out);
        if (!out.is_open())
        {
            ELOG("无法打开文件 %s 进行写入", _filename.c_str());
            return -1;
        }

        // 先尝试定位到 pos 位置
        if (!out.seekp(pos))
        {
            ELOG("文件 %s 的偏移 %zu 无效", _filename.c_str(), pos);
            out.close();
            return -1;
        }

        // 写入数据
        out.write(buffer.data(), len);
        if (!out)
        {
            ELOG("文件 %s 写入失败", _filename.c_str());
            out.close();
            return -1;
        }
        out.close();

        return len;
    }

    // **重载函数：写入整个 buffer**
    int write(const std::string &buffer)
    {
        std::ofstream out(_filename, std::ios::binary | std::ios::trunc);
        if (!out.is_open())
        {
            ELOG("无法打开文件 %s 进行写入", _filename.c_str());
            return -1;
        }

        // 直接写入整个字符串
        out.write(buffer.data(), buffer.size());
        if (!out)
        {
            ELOG("文件 %s 写入失败", _filename.c_str());
            out.close();
            return -1;
        }
        out.close();

        return buffer.size();
    }

    static bool renameFile(const std::string &old_name, const std::string &new_name)
    {
        if (std::rename(old_name.c_str(), new_name.c_str()) != 0)
        {
            ELOG("文件重命名失败: %s -> %s", old_name.c_str(), new_name.c_str());
            return false;
        }
        return true;
    }

    static std::string getParentDirectory(const std::string &path)
    {
        try
        {
            std::filesystem::path p(path);
            return p.parent_path().string(); // 获取父目录路径
        }
        catch (const std::exception &e)
        {
            ELOG("获取父目录失败: %s", e.what());
            return "";
        }
    }

    static bool createFile(const std::string &filename)
    {
        std::ofstream file(filename, std::ios::binary);
        if (!file)
        {
            ELOG("无法创建文件: %s", filename.c_str());
            return false;
        }
        file.close(); // 关闭文件
        return true;
    }

    static bool deleteFile(const std::string &filename)
    {
        if (std::remove(filename.c_str()) != 0)
        {
            ELOG("无法删除文件: %s", filename.c_str());
            return false;
        }
        return true;
    }

    static bool createDirectory(const std::string &dir)
    {
        try
        {
            // 创建多级目录
            if (std::filesystem::create_directories(dir))
            {
                return true;
            }
            else
            {
                ELOG("目录已存在或无法创建: %s", dir.c_str());
                return false;
            }
        }
        catch (const std::exception &e)
        {
            ELOG("创建目录失败: %s", e.what());
            return false;
        }
    }

    static bool deleteDirectory(const std::string &dir)
    {
        try
        {
            // 递归地删除层级目录及其目录中的所有文件
            if (std::filesystem::remove_all(dir) > 0)
            {
                return true;
            }
            else
            {
                ELOG("删除目录失败或目录不为空: %s", dir.c_str());
                return false;
            }
        }
        catch (const std::exception &e)
        {
            ELOG("删除目录失败: %s", e.what());
            return false;
        }
    }

    // bool delete_directory(const std::string &dir, std::string &error_message)
    // {
    //     std::error_code ec;
    //     size_t removed_count = std::filesystem::remove_all(dir, ec);

    //     if (ec) // 如果错误码不为空，表示删除失败
    //     {
    //         error_message = "删除目录失败: " + ec.message();
    //         return false;
    //     }
    //     else if (removed_count == 0) // 目录可能为空或不存在
    //     {
    //         error_message = "删除目录失败或目录为空: " + dir;
    //         return false;
    //     }

    //     return true;
    // }

    ~FileHelper() {}

private:
    std::string _filename;
};

int main()
{
    // FileHelper file_helper("../../mqcommon/logger.hpp");
    // std::string log;
    // file_helper.read(log);
    // std::cout << log << std::endl;

    // std::string path("./aaa/bbb/ccc/ddd/tmp.hpp");

    // FileHelper fh(path);

    // if (fh.exist())
    // {
    //     std::string tmp("1234567890");
    //     fh.write(tmp, 8, 12);
    // }
    // else
    // {
    //     std::string parentdirect = FileHelper::getParentDirectory(path);
    //     if (FileHelper::createDirectory(parentdirect))
    //     {
    //         FileHelper::createFile(path);

    //         FileHelper file_helper("../../mqcommon/logger.hpp");
    //         std::string log;
    //         file_helper.read(log);
    //         fh.write(log);
    //     }
    // }

    std::string path("./aaa/bbb/ccc/ddd/test.hpp");
    FileHelper fh(path);
    // std::cout << fh.size() << std::endl;

    // FileHelper::renameFile(path, "./aaa/bbb/ccc/ddd/test.hpp");
    FileHelper::deleteDirectory("aaa");
    // FileHelper::deleteFile(test.)

    return 0;
}